/**
 * Draws a texture
 * Each texture has:
 *   a color, which is drawn within the bounds of the coordinates
 *   an image, which is merged with the color
 *   post_effects, which is an ArrayList of strings representing post effects to be drawn with the pf_(methodname) methods
 */
class tTexture
{
  PImage my_image;
  public color my_color;
  int original_alpha;
  int original_stroke_alpha;
  ArrayList my_post_effects;
  boolean has_color;
  color my_stroke_color;
  
  tTexture()
  {
    my_image = null;
    has_color = false;
    my_post_effects = null;
  }
  
  /**
   * Call when first creating the tTexture
   * @param in_color set the properties for the tTexture
   */
  tTexture(color in_color)
  {
    my_image = null;
    my_color = in_color;
    original_alpha = (int)alpha(my_color);
    my_post_effects = null;
    has_color = true;
    set_stroke_color();
  }
  
  /**
   * Call when first creating the tTexture
   * @param in_image set the properties for the tTexture
   * @param in_color set the properties for the tTexture
   * @param in_post_effects set the properties for the tTexture
   */
  tTexture(color in_color, PImage in_image, ArrayList in_post_effects)
  {
    my_image = in_image;
    my_color = in_color;
    original_alpha = (int)alpha(my_color);
    my_post_effects = in_post_effects;
    has_color = true;
    set_stroke_color();
  }
  
  /**
   * Call to draw the texture on the specified coordinates
   * @coords a list of coordinates for a convex shape,
   *   where each coordinate is an int array[2]
   * @position the [x,y] position of the coords on the screen
   * @return the same as draw_post_effects()
   */
  boolean doDraw(int coords[][], int position[])
  {
    draw_color_image(coords, position);
    if (my_post_effects != null)
    {
      return draw_post_effects(coords, position);
    }
    return true;
  }
  
  /**
   * Sets the color for the stroke of the texture
   * Only works if a color was set for the texture
   * defaults to half the value of the input color
   */
  void set_stroke_color()
  {
    if (has_color)
    {
      this.set_stroke_color(color((red(my_color)+0)/2, (green(my_color)+0)/2, (blue(my_color)+0)/2));
    }
  }
  
  /**
   * Sets the color for the stroke of the texture
   * Only works if a color was set for the texture
   * @param in_stroke_color the color to set the stroke to
   */
  void set_stroke_color(color in_stroke_color)
  {
    my_stroke_color = in_stroke_color;
    original_stroke_alpha = (int)alpha(my_stroke_color);
  }
  
  /**
   * creates the basic shape, with this tTexture's color
   * @coords a list of coordinates for a convex shape,
   *   where each coordinate is an int array[2]
   * @pos the [x,y] position of the coords on the screen
   * @in_image the image drawn with draw_color() and draw_image()
   */
  void draw_color_image(int coords[][], int pos[])
  {
    textureMode(NORMALIZED);
    float image_vertices[][] = {{0f,0f}, {1f,0f}, {1f,1f}, {0f,1f}};
    boolean texture_works = false;
    
    beginShape();
    
    if (my_image != null)
    {
      texture(my_image);
      texture_works = true;
    }
    if (has_color)
    {
      fill(my_color);
      //stroke(my_stroke_color);
      noStroke();
    }
    
    for (int i = 0; i < coords.length; i++)
    {
      float image_vertex[] = image_vertices[min(i,image_vertices.length-1)];
      if (texture_works)
      {
        vertex(coords[i][0]+pos[0], coords[i][1]+pos[1], image_vertex[0], image_vertex[1]);
      }
      else
      {
        vertex(coords[i][0]+pos[0], coords[i][1]+pos[1]);
      }
    }
    
    endShape();
    
    //line(coords[0][0]+pos[0], coords[0][1]+pos[1], coords[coords.length-1][0]+pos[0], coords[coords.length-1][1]+pos[1]);
  }
  
  /**
   * draws the post effects for the tTexture directly to the screen
   * @coords the coordinates of the shapes
   * @position the position of the 0 coordinate in coords
   * @return false if any of the post effects fail
   */
  boolean draw_post_effects(int coords[][], int position[])
  {
    for (int pf_i = 0; pf_i < my_post_effects.size(); pf_i++)
    {
      boolean retval = true;
      String pf_type = my_post_effects.get(pf_i).toString();
      if (pf_type == "pf_highlighted_corners")
      {
        retval = pf_highlighted_corners(coords, 5, color(255,255,255));
        break;
      }
      /*else if (pf_type == "pf_something_else_here")
      {
      }*/
      if (!retval)
      {
        return false;
      }
    }
    
    return true;
  }
  
  /**
   * adds a glow effect around every coordinate
   * draws the post effect directly to the screen
   * @coords the coordinates to draw at, where each coordinate is an array [x,y]
   * @rad the radius of the glow
   * @glow_color the rgb color (alpha = 255) of the glow
   * @return true on success, false otherwise
   */
  boolean pf_highlighted_corners(int coords[][], int rad, color glow_color)
  {
    
    return true;
  }
  
  /**
   * multiplies the input alpha by the original alpha value
   * @param alphaVal should be between 0 and 255
   */
  void setAlpha(int alphaVal)
  {
    float a = original_alpha;
    int new_alpha = (int)(((float)alphaVal/255.0)*a);
    my_color = color(red(my_color), green(my_color), blue(my_color), new_alpha );
    a = original_stroke_alpha;
    new_alpha = (int)(((float)alphaVal/255.0)*a);
    my_stroke_color = color(red(my_stroke_color), green(my_stroke_color), blue(my_stroke_color), new_alpha );
  }
  
  /**
   * permanently changes the color of the texture
   * also changes the stroke color
   * @param newColor the new color
   */
  void changeColor(color newColor)
  {
    my_color = newColor;
    set_stroke_color();
  }
}

/**
 * Returns an array of four tTextures, where the indexes correspond to:
 *   0: normal
 *   1: hovered
 *   2: active
 *   3: hidden
 * @param base_color the basic color of the texture
 * @return a tTexture[4] array
 */
tTexture[] standard_tTexture_palette(color base_color)
{
  tTexture retval[] = {
    standard_normal_tTexture(base_color),
    standard_hovered_tTexture(base_color),
    standard_active_tTexture(base_color),
    standard_hidden_tTexture(base_color),
  };
  return retval;
}

/**
 * Returns the standard texture for a normal tangram
 * @param texture_color the base color for the texture
 * a suggested color is color(210,180,140)
 * @return a standard texture
 */
tTexture standard_normal_tTexture(color texture_color)
{
  return new tTexture(texture_color);
}

/**
 * Returns the standard texture for a hovered tangram
 * @param texture_color the base color for the texture
 * a suggested color is color(210,180,140)
 * @return a standard texture
 */
tTexture standard_hovered_tTexture(color texture_color)
{
  int high = (int)max( max(red(texture_color), green(texture_color)), blue(texture_color) );
  int diff = 255 - high;
  int newColors[] = { (int)red(texture_color), (int)green(texture_color), (int)blue(texture_color) };
  for (int i = 0; i < newColors.length; i++)
  {
    int colDiff = (255-newColors[i])/2;
    if (colDiff < 50 && colDiff < diff)
    {
      colDiff = diff;
    }
    newColors[i] += colDiff;
  }
  texture_color = color(newColors[0], newColors[1], newColors[2], alpha(texture_color));
  return new tTexture(texture_color);
}

/**
 * Returns the standard texture for a active tangram
 * @param texture_color the base color for the texture
 * a suggested color is color(210,180,140)
 * @return a standard texture
 */
tTexture standard_active_tTexture(color texture_color)
{
  texture_color = color(red(texture_color)/4*3, green(texture_color)/4*3, blue(texture_color)/4*3, alpha(texture_color));
  return new tTexture(texture_color);
}

/**
 * Returns the standard texture for a hidden tangram
 * @param texture_color the base color for the texture
 * a suggested color is color(210,180,140)
 * @return a standard texture
 */
tTexture standard_hidden_tTexture(color texture_color)
{
  texture_color = color(red(texture_color), green(texture_color), blue(texture_color), 0);
  return new tTexture(texture_color);
}
